/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package UI;

import java.awt.event.KeyEvent;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.junit.Test;
import static org.junit.Assert.*;
import java.awt.*;
import javax.swing.*;
import Rendering.Utils.*;
import Rendering.IViewerHost;
import Rendering.MapViewer;
import Core.*;
import Data.FileMapProvider;
import Data.RoadLayer;
import Rendering.ActionType;
import Rendering.Editor.LineEditor;
import Rendering.Editor.NodeEditor;
import Rendering.IObjectInfo;
import Rendering.IRenderer;
import Rendering.Info.LinkInfo;
import Rendering.Info.NodeInfo;
import Rendering.Info.StreetInfo;
import Rendering.Info.StreetPointInfo;
import Rendering.InfoType;
import Rendering.Renderers.StreetRenderer;
import java.awt.event.KeyListener;
import java.lang.Thread;
import java.util.Iterator;
import RenderingTests.ImageRendererTests;
import Rendering.Editor.LineEditor;
import Rendering.Editor.NodeEditor;
import Rendering.Editor.MarkerEditor;
import Rendering.Renderers.MarkerRenderer;
import Rendering.Renderers.StreetRenderer;
import java.util.ArrayList;

public class PanelViewer extends JPanel implements IViewerHost {
    //IMapProvider provider;
    FileMapProvider provider;
    boolean debug_;
    LineEditor lineEditor_;
    NodeEditor nodeEditor_;
    MarkerEditor markerEditor_;
    RoadLayer streetLayer_;
    MapViewer viewer_;

    public PanelViewer()
    {
        
        
        //this.setMaximumSize(new Dimension());
        //this.setMinimumSize(new Dimension(1000,600));
        
        //this.setSize(viewer_.getSize());
        this.setLayout(new BorderLayout());
        this.setLocation(0,0);
        this.setPreferredSize(new Dimension(600,600));
       
        //this.setSize(new Dimension(800,600));
        
        //provider = new MockMapProvider();
        /*provider = new FileMapProvider();

        try
        {
        provider.Load("C:\\test(2).map");
        }
        catch(Exception e)
        {
            e.printStackTrace();

        }*/
        
        MapViewer viewer = new MapViewer(this);
        this.SetViewer(viewer);
        //viewer.LoadMap(provider);
        //this.add(viewer);
        this.add(viewer, BorderLayout.CENTER);

        //viewer.SetSize(this.getSize().height, this.getSize().width);
        System.out.println("height:" + this.getSize().height + " width:" + this.getSize().width);
        //System.out.println("height:" + this.getPreferredSize().height + " width:" + this.getPreferredSize().width);

        //this.addKeyListener(this);

        
       
        KeyboardFocusManager.getCurrentKeyboardFocusManager()
            .addKeyEventDispatcher(new KeyEventDispatcher()
            {
                public boolean dispatchKeyEvent(KeyEvent e) {
                    if (e.getID() == KeyEvent.KEY_PRESSED) {
                        if (e.getKeyCode() == KeyEvent.VK_LEFT) {
                            viewer_.Pan(new Core.Point(-512, 0), 500);
                            return true;
                        }
                        if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
                            viewer_.Pan(new Core.Point(512, 0), 500);
                            return true;
                        }
                        if (e.getKeyCode() == KeyEvent.VK_DOWN) {
                            viewer_.Pan(new Core.Point(0, 512), 500);
                            return true;
                        }
                        if (e.getKeyCode() == KeyEvent.VK_UP) {
                            viewer_.Pan(new Core.Point(0, -512), 500);
                            return true;
                        }
                        else if(e.getKeyCode() == KeyEvent.VK_D && e.isControlDown()) {
                            viewer_.SetDebug(!debug_);
                            debug_ = !debug_;
                        }
                    }

                    return false;
                }
            });
    }

    public void SeteazaMarimea(int width, int height)
    {
        this.setPreferredSize(new Dimension(width, height));
        revalidate(); //pentru a redesena panel-ul

    }

    public IMapProvider Provider() { return provider; }
    public void setProvider(FileMapProvider newprovider) { provider = newprovider;}
    public MapViewer Viewer() { return viewer_; }
    public void setViewer(MapViewer viewer) { viewer_ = viewer; }
        
        IObjectInfo selected_;

        void SetViewer(MapViewer viewer) {
            viewer_ = viewer;
            //this.addKeyListener(this);
        }


        public void ShowLayer(ILayer layer) {
            viewer_.ShowLayer(layer, 500);
        }

        public void HideLayer(ILayer layer) {
            viewer_.HideLayer(layer, 500);
        }

        // ######### !!!!!!!!!! ###############
        public void ActionPerformed(Action action) {
        }

        public void ActionPerformed(Rendering.Action action) {
            System.out.println(action.toString());

            if(action.Type() == ActionType.ObjectMoved) {
                // UN OBIECT A FOST MUTAT.
                if(action.ObjectInfo().Type() == InfoType.StreetPoint) {
                    // Actualizeaza coordonata punctului in layer-ul parinte.
                    StreetPointInfo spi = (StreetPointInfo)action.ObjectInfo();
                    spi.Street().Coordinates().set(spi.PointIndex(), spi.Coordinates());
                }

                else if(action.ObjectInfo().Type() == InfoType.Node) {
                    NodeInfo node = (NodeInfo)action.ObjectInfo();
                }
            }
            if(action.Type() == ActionType.ObjectAdded) {
                if(action.ObjectInfo().Type() == InfoType.StreetPoint) {
                    // Adauga punctul la strada asociata.
                    StreetPointInfo spi = (StreetPointInfo)action.ObjectInfo();
                    spi.Street().Coordinates().add(spi.PointIndex(), spi.Coordinates());
                }
                else if(action.ObjectInfo().Type() == InfoType.Street) {
                    // Adauga o noua strada la layer. Primul punct va fi adaugat ulterior.
                    StreetInfo si = (StreetInfo)action.ObjectInfo();
                    streetLayer_.AddStreet(si.Street());
                }
                else if (action.ObjectInfo().Type() == InfoType.Node)
                {
                    Node node = (Node)action.ObjectInfo();

                }

            }
            else if(action.Type() == ActionType.ObjectSelected) {
                 selected_ = action.ObjectInfo();
            }
        }

    /*private void HideEditors() {
        if(markerEditor_ != null) {
            viewer_.HideLayer(markerEditor_, 0);
        }
        if(nodeEditor_ != null) {
            viewer_.HideLayer(nodeEditor_, 0);
        }
        if(lineEditor_ != null) {
            viewer_.HideLayer(lineEditor_, 0);
        }
    }*/

     public void HideEditors() {
        if(markerEditor_ != null) {
            viewer_.HideLayer(markerEditor_, 0);
        }
        if(nodeEditor_ != null) {
            viewer_.HideLayer(nodeEditor_, 0);
        }
        if(lineEditor_ != null) {
            viewer_.HideLayer(lineEditor_, 0);
        }
    }
      public void RemoveEditors() {
        if(markerEditor_ != null) {
            viewer_.RemoveRenderer(markerEditor_);
            markerEditor_ = null;

        }
        if(nodeEditor_ != null) {
            viewer_.RemoveRenderer(nodeEditor_);
            nodeEditor_ = null;
        }
        if(lineEditor_ != null) {
            viewer_.RemoveRenderer(lineEditor_);
            lineEditor_ = null;
        }
    }


    public void CreateStreetEditor() {
        StreetRenderer streetRend = null;

        if (lineEditor_ == null) {
            Iterator<IRenderer> rendIt = viewer_.Renderers();
            while (rendIt.hasNext()) {
                IRenderer r = rendIt.next();
                if (r.Layer().Type() == LayerType.Street) {
                    streetRend = (StreetRenderer) r;
                    streetLayer_ = (RoadLayer)r.Layer(); // Obtine layer-ul de strazi.
                    lineEditor_ = new LineEditor(streetRend, viewer_);
                    viewer_.AddRenderer(lineEditor_);
                    break;
                }
            }
        }

        HideEditors();
        lineEditor_.SetOpacity(1.0);
        lineEditor_.SetVisible(true);
        viewer_.Repaint();
    }

    public void CreateNodeEditor() {
        // Editorul de strazi trebuie sa fie creat.
        CreateStreetEditor();

        if (nodeEditor_ == null) {
            nodeEditor_ = new NodeEditor(lineEditor_, viewer_);
            viewer_.AddRenderer(nodeEditor_);
        }

        HideEditors();
        lineEditor_.SetOpacity(0.15);
        nodeEditor_.SetOpacity(1.0);
        nodeEditor_.SetVisible(true);
        viewer_.Repaint();

    }

     public void CreateMarkerEditor() {
        // Editorul de strazi trebuie sa fie creat.
        CreateNodeEditor();
         if(markerEditor_ == null)
         {

         ArrayList<MarkerRenderer> markerRend = new ArrayList<MarkerRenderer>();
         Iterator<IRenderer> rendIt = viewer_.Renderers();
         while(rendIt.hasNext())
         {
             IRenderer test = rendIt.next();
             if(test.Layer() != null)
             {
                 if(test.Layer().Type() == LayerType.Marker)
                 {
                      markerRend.add((MarkerRenderer)test);
                 }
             }
          }
         markerEditor_ = new MarkerEditor(markerRend, nodeEditor_, viewer_);
         viewer_.AddRenderer(markerEditor_);
         }

         HideEditors();
         markerEditor_.SetVisible(true);
         markerEditor_.SetOpacity(1.0);
         viewer_.Repaint();

    }
    
}
